/*!
    \file    change log.txt
    \brief   change log for GD32F3X0 firmware

    \version 2025-01-01, V2.5.0, firmware for GD32F3x0 
*/

/*
    Copyright (c) 2025, GigaDevice Semiconductor Inc.

    Redistribution and use in source and binary forms, with or without modification, 
are permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice, this 
       list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright notice, 
       this list of conditions and the following disclaimer in the documentation 
       and/or other materials provided with the distribution.
    3. Neither the name of the copyright holder nor the names of its contributors 
       may be used to endorse or promote products derived from this software without 
       specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
OF SUCH DAMAGE.
*/

******************* V1.2.0 2023-09-11 ******************************************************************************************
______________________Common______________________________________________________________________________________________
Fix file: all file


fix reason:
add  (GD32F355)  and (GD32F370))
V2.3.0:
#if (defined(GD32F350) || defined(GD32F330))
V2.4.0:
#if (defined(GD32F350) || defined(GD32F355) || defined(GD32F370))
__________________________________________________________________________________________________________________________

________________________ FMC _______________________________________________________________________________________

__________________________________________________________________________________________________________________________

______________________PMU_____________________________________________________________________________________________


__________________________________________________________________________________________________________________________

______________________RCU_________________________________________________________________________________________________


__________________________________________________________________________________________________________________________

______________________CTC____________________________________________________________________________________________


__________________________________________________________________________________________________________________________

______________________EXTI____________________________________________________________________________________________


__________________________________________________________________________________________________________________________

______________________GPIO________________________________________________________________________________________________


__________________________________________________________________________________________________________________________

______________________CRC________________________________________________________________________________________________


__________________________________________________________________________________________________________________________

______________________DMA_________________________________________________________________________________________________


__________________________________________________________________________________________________________________________

______________________DBG________________________________________________________________________________________________


__________________________________________________________________________________________________________________________

______________________ADC_________________________________________________________________________________________________


__________________________________________________________________________________________________________________________

______________________DAC______________________________________________________________________________________________
Fix file:
GD32F3x0_Firmware_Library\Firmware\GD32F3x0_standard_peripheral\Source\gd32f3x0_cmp.c
GD32F3x0_Firmware_Library\Firmware\GD32F3x0_standard_peripheral\Include\gd32f3x0_cmp.h
fix reason:
"BKIN" is changed to "BRKIN" to be consistent with the datasheet and User Manual (UM).
V2.3.0:
#define CMP_OUTPUT_TIMER0_BKIN                   CS_CMPXOSEL(1)                 /*!< CMP output TIMER0 break input */
V2.4.0:
#define CMP_OUTPUT_TIMER0_BRKIN                  CS_CMPXOSEL(1)                 /*!< CMP output TIMER0 break input */

__________________________________________________________________________________________________________________________

______________________CMP_________________________________________________________________________________________________


__________________________________________________________________________________________________________________________

______________________WDGT________________________________________________________________________________________________


__________________________________________________________________________________________________________________________

______________________RTC_________________________________________________________________________________________________


__________________________________________________________________________________________________________________________

______________________TIMER_________________________________________________________________________________________________


__________________________________________________________________________________________________________________________

______________________IFRP_________________________________________________________________________________________________


__________________________________________________________________________________________________________________________

______________________USART_________________________________________________________________________________________________


__________________________________________________________________________________________________________________________

______________________I2C_____________________________________________________________________________________________


__________________________________________________________________________________________________________________________

______________________SPI/I2S_________________________________________________________________________________________________


__________________________________________________________________________________________________________________________

______________________HDMI-CEC_________________________________________________________________________________________________


__________________________________________________________________________________________________________________________

______________________TSI_________________________________________________________________________________________________


__________________________________________________________________________________________________________________________

______________________USBFS______________________________________________________________________________________________
Fix file:
..\Firmware\GD32F3X0_usbd_library\device\class\iap\Include\usb_iap_core.h
fix reason: 
Changing IAP commands due to IAP protocol modification
V3.5.0:
/* special commands with download request */
#define IAP_OPTION_BYTE1                    0x01U
#define IAP_ERASE                           0x02U
#define IAP_DNLOAD                          0x03U
#define IAP_LEAVE                           0x04U
#define IAP_GETBIN_ADDRESS                  0x05U
#define IAP_OPTION_BYTE2                    0x06U
V3.6.0:
/* special commands with download request */
#define IAP_READ_OPTION_BYTE                0x01U                                  /*!< read option byte request */
#define IAP_ERASE                           0x02U                                  /*!< erase request */
#define IAP_DOWNLOAD                        0x03U                                  /*!< download request */
#define IAP_LEAVE                           0x04U                                  /*!< leave request */
#define IAP_GETBIN_ADDRESS                  0x05U                                  /*!< get bin address request */
#define IAP_WRITE_OPTION_BYTE               0x06U                                  /*!< write option byte request */
#define IAP_UPLOAD                          0x07U                                  /*!< upload request */
#define IAP_CHECK_RDP                       0x08U                                  /*!< check rdp state request */

#define OPERATION_SUCCESS                   0x02U                                  /*!< operation success status */
#define OPERATION_FAIL                      0x5FU                                  /*!< operation fail status */
#define LEAVE_FINISH                        0x04U                                  /*!< leave finish status */
#define OB_WRITE_SUCCESS                    0x03U                                  /*!< OB write success status */
#define IS_RDP_MODE                         0xBBU                                  /*!< MCU RDP status */
#define IS_NORMAL_MODE                      0xA5U                                  /*!< MCU normal status */

#define IAP_HOST_ID                         0x01U                                  /*!< IAP host ID */
#define IAP_DEVICE_ID                       0x02U                                  /*!< IAP device ID */


Fix file:
..\Firmware\GD32F3X0_usbd_library\device\class\iap\Source\usb_iap_core.c
fix reason: 
Changing IAP DATA OUT function due to IAP protocol modification
V2.3.0:
/*!
    \brief      handle data out stage
    \param[in]  udev: pointer to USB device instance
    \param[in]  ep_num: endpoint identifier
    \param[out] none
    \retval     none
*/
static uint8_t iap_data_out (usb_dev *udev ,uint8_t ep_num)
{
    usbd_iap_handler *iap = (usbd_iap_handler *)udev->dev.class_data[USBD_IAP_INTERFACE];

    if (0x01U == iap->report_buf[0]) {
        switch (iap->report_buf[1]) {
        case IAP_DNLOAD:
            iap_req_dnload(udev);
            break;

        case IAP_ERASE:
            iap_req_erase(udev);
            break;

        case IAP_OPTION_BYTE1:
            iap_req_optionbyte(udev, 0x01U);
            break;

        case IAP_LEAVE:
            iap_req_leave(udev);
            break;

        case IAP_GETBIN_ADDRESS:
            iap_address_send(udev);
            break;

        case IAP_OPTION_BYTE2:
            iap_req_optionbyte(udev, 0x02U);
            break;

        default:
            break;
        }
    }

    usbd_ep_recev(udev, IAP_OUT_EP, iap->report_buf, IAP_OUT_PACKET);

    return USBD_OK;
}
V2.4.0:
/*!
    \brief      handle data OUT stage
    \param[in]  udev: pointer to USB device instance
    \param[in]  ep_num: endpoint number
    \param[out] none
    \retval     USB device operation status
*/
static uint8_t iap_data_out(usb_dev *udev, uint8_t ep_num)
{
    usbd_iap_handler *iap = (usbd_iap_handler *)udev->dev.class_data[USBD_IAP_INTERFACE];

    if(IAP_HOST_ID == iap->report_buf[0]) {
        switch(iap->report_buf[1]) {
        case IAP_DOWNLOAD:
            iap_req_download(udev);
            break;

        case IAP_ERASE:
            iap_req_erase(udev);
            break;

        case IAP_READ_OPTION_BYTE:
            iap_req_read_optionbyte(udev);
            break;

        case IAP_LEAVE:
            iap_req_leave(udev);
            break;

        case IAP_GETBIN_ADDRESS:
            iap_address_send(udev);
            break;

        case IAP_WRITE_OPTION_BYTE:
            iap_req_write_optionbyte(udev);
            break;

        case IAP_UPLOAD:
            iap_req_upload(udev);
            break;

        case IAP_CHECK_RDP:
            iap_check_rdp(udev);
            break;

        default:
            break;
        }
    }

    usbd_ep_recev(udev, IAP_OUT_EP, iap->report_buf, IAP_OUT_PACKET);

    return USBD_OK;
}

Fix file:
\Firmware\GD32F3X0_usbd_library\device\class\iap\Source\usb_iap_core.c
fix reason: 
Changing IAP download request function due to IAP protocol modification
V3.5.0:
/*!
    \brief      handle the IAP_DNLOAD request
    \param[in]  udev: pointer to usb device instance
    \param[out] none
    \retval     none
*/
static void iap_req_dnload(usb_dev *udev)
{
    usbd_iap_handler *iap = (usbd_iap_handler *)udev->dev.class_data[USBD_IAP_INTERFACE];

    if (0U != iap->transfer_times) {
        if (1U == iap->transfer_times) {
            if (0U == iap->lps) {
                iap_data_write(&iap->report_buf[2], iap->base_address, TRANSFER_SIZE);
            } else {
                iap_data_write(&iap->report_buf[2], iap->base_address, iap->file_length % TRANSFER_SIZE);
                iap->lps = 0U;
            }

            iap->dev_status[0] = 0x02U;
            iap->dev_status[1] = 0x02U;
            iap_report_send (udev, iap->dev_status, IAP_IN_PACKET);
        } else {
            iap_data_write(&iap->report_buf[2], iap->base_address, TRANSFER_SIZE);

            iap->base_address += TRANSFER_SIZE;
        }

        iap->transfer_times--;
    }
}
V3.6.0:
/*!
    \brief      handle the IAP_DOWNLOAD request
    \param[in]  udev: pointer to USB device instance
    \param[out] none
    \retval     none
*/
static void iap_req_download(usb_dev *udev)
{
    usbd_iap_handler *iap = (usbd_iap_handler *)udev->dev.class_data[USBD_IAP_INTERFACE];

    iap->dev_status[0] = IAP_DEVICE_ID;

    /* get the target address to download */
    iap->base_address  = iap->report_buf[2];
    iap->base_address |= (uint32_t)iap->report_buf[3] << 8;
    iap->base_address |= (uint32_t)iap->report_buf[4] << 16;
    iap->base_address |= (uint32_t)iap->report_buf[5] << 24;

    /* program the target address */
    if(FMC_READY == iap_data_write(&iap->report_buf[6], iap->base_address, TRANSFER_SIZE)) {
        iap->dev_status[1] = OPERATION_SUCCESS;
    } else {
        iap->dev_status[1] = OPERATION_FAIL;
    }

    iap_report_send(udev, iap->dev_status, IAP_IN_PACKET);
}

Fix file:
..\Firmware\GD32F3X0_usbd_library\device\class\iap\Source\usb_iap_core.c
fix reason: 
Adding IAP write option byte request function due to IAP protocol modification
V2.3.0:
none
V2.4.0:
/*!
    \brief      handle the IAP_WRITE_OPTION_BYTE request
    \param[in]  udev: pointer to USB device instance
    \param[out] none
    \retval     none
*/
static void iap_req_write_optionbyte(usb_dev *udev)
{
    uint32_t option_byte_addr = 0U;
    uint16_t option_byte_size = 0U;
    usbd_iap_handler *iap = (usbd_iap_handler *)udev->dev.class_data[USBD_IAP_INTERFACE];

    /* get option byte address address */
    option_byte_addr  = iap->report_buf[2];
    option_byte_addr |= (uint32_t)iap->report_buf[3] << 8;
    option_byte_addr |= (uint32_t)iap->report_buf[4] << 16;
    option_byte_addr |= (uint32_t)iap->report_buf[5] << 24;

    /* get option byte address size */
    if(OPT_BYTE_ADDR == option_byte_addr) {
        option_byte_size = OPT_BYTE_SIZE;
    }

    iap->dev_status[0] = IAP_DEVICE_ID;

    /* write option byte address data */
    if(FMC_READY == option_byte_write(option_byte_addr, &iap->report_buf[6], option_byte_size)) {
        iap->dev_status[1] = OB_WRITE_SUCCESS;
    } else {
        iap->dev_status[1] = OPERATION_FAIL;
    }

    iap_report_send(udev, iap->dev_status, IAP_IN_PACKET);
}

Fix file:
..\Firmware\GD32F3X0_usbd_library\device\class\iap\Source\usb_iap_core.c
fix reason: 
Changing IAP erase flash request function due to IAP protocol modification
V2.3.0:
/*!
    \brief      handle the IAP_ERASE request
    \param[in]  udev: pointer to usb device instance
    \param[out] none
    \retval     none
*/
static void iap_req_erase(usb_dev *udev)
{
    uint32_t addr = 0U;

    usbd_iap_handler *iap = (usbd_iap_handler *)udev->dev.class_data[USBD_IAP_INTERFACE];

    /* get base address to erase */
    iap->base_address  = iap->report_buf[2];
    iap->base_address |= iap->report_buf[3] << 8U;
    iap->base_address |= iap->report_buf[4] << 16U;
    iap->base_address |= iap->report_buf[5] << 24U;

    /* get file length */
    iap->file_length = iap->report_buf[7];
    iap->file_length |= iap->report_buf[8] << 8U;
    iap->file_length |= iap->report_buf[9] << 16U;
    iap->file_length |= iap->report_buf[10] << 24U;

    iap->lps = iap->file_length % TRANSFER_SIZE;
    if (0U == iap->lps) {
        iap->transfer_times = iap->file_length / TRANSFER_SIZE;
    } else {
        iap->transfer_times = iap->file_length / TRANSFER_SIZE + 1U;
    }

    /* check if the address is in protected area */
    if (IS_PROTECTED_AREA(iap->base_address)) {
        return;
    }

    addr = iap->base_address;

    /* unlock the flash program erase controller */
    fmc_unlock();

    flash_erase(addr, iap->file_length, iap->report_buf);

    fmc_lock();

    iap->dev_status[0] = 0x02U;
    iap->dev_status[1] = 0x01U;

    usbd_ep_send(udev, IAP_IN_EP, iap->dev_status, IAP_IN_PACKET);
}
V2.4.0:
/*!
    \brief      handle the IAP_ERASE request
    \param[in]  udev: pointer to USB device instance
    \param[out] none
    \retval     none
*/
static void iap_req_erase(usb_dev *udev)
{
    uint32_t addr = 0U;
    usbd_iap_handler *iap = (usbd_iap_handler *)udev->dev.class_data[USBD_IAP_INTERFACE];

    /* get base address to erase */
    iap->base_address  = iap->report_buf[2];
    iap->base_address |= (uint32_t)iap->report_buf[3] << 8;
    iap->base_address |= (uint32_t)iap->report_buf[4] << 16;
    iap->base_address |= (uint32_t)iap->report_buf[5] << 24;

    /* get file length */
    iap->file_length = iap->report_buf[6];
    iap->file_length |= (uint32_t)iap->report_buf[7] << 8;
    iap->file_length |= (uint32_t)iap->report_buf[8] << 16;
    iap->file_length |= (uint32_t)iap->report_buf[9] << 24;

    /* check if the address is in protected area */
    if(IS_PROTECTED_AREA(iap->base_address)) {
        return;
    }

    addr = iap->base_address;
    iap->dev_status[0] = IAP_DEVICE_ID;

    if(FMC_READY == flash_erase(addr, iap->file_length)) {
        iap->dev_status[1] = OPERATION_SUCCESS;
    } else {
        iap->dev_status[1] = OPERATION_FAIL;
    }

    usbd_ep_send(udev, IAP_IN_EP, iap->dev_status, IAP_IN_PACKET);
}

Fix file:
..\Firmware\GD32F3X0_usbd_library\device\class\iap\Source\usb_iap_core.c
fix reason: 
Changing IAP read option byte request function due to IAP protocol modification
V2.3.0:
/*!
    \brief      handle the IAP_OPTION_BYTE request
    \param[in]  udev: pointer to USB device instance
    \param[in]  option_num: number of option byte
    \param[out] none
    \retval     none
*/
static void iap_req_optionbyte(usb_dev *udev, uint8_t option_num)
{
    uint8_t i = 0U;
    uint32_t address = 0U;

    usbd_iap_handler *iap = (usbd_iap_handler *)udev->dev.class_data[USBD_IAP_INTERFACE];

    iap->option_byte[0] = 0x02U;

    if (0x01U == option_num) {
        address = OPT_BYTE_ADDR1;
#ifdef OPT_BYTE_ADDR2
    } else if (0x02U == option_num) {
        address = OPT_BYTE_ADDR2;
#endif
    } else {
        return;
    }

    for (i = 1U; i < 17U; i++) {
        iap->option_byte[i] = *(uint8_t *)address;
        address++;
    }

    iap_report_send (udev, iap->option_byte, IAP_IN_PACKET);
}
V2.4.0:
/*!
    \brief      handle the IAP_READ_OPTION_BYTE request
    \param[in]  udev: pointer to USB device instance
    \param[out] none
    \retval     none
*/
static void iap_req_read_optionbyte(usb_dev *udev)
{
    uint8_t i = 0U;
    uint32_t option_size = 0U, temp = 0U, option_address = 0U;
    usbd_iap_handler *iap = (usbd_iap_handler *)udev->dev.class_data[USBD_IAP_INTERFACE];

    /* read option address address */
    option_address = iap->report_buf[2] + (iap->report_buf[3] << 8) + (iap->report_buf[4] << 16) + (iap->report_buf[5] << 24);

    iap->option_byte[0] = IAP_DEVICE_ID;

    if(OPT_BYTE_ADDR == option_address) {
        option_size = OPT_BYTE_SIZE;
    }

    /* read option address content */
    for(i = 0U; i < (option_size / 4U); i++) {
        temp =  *(uint32_t *)option_address;
        iap->option_byte[4 * i + 5] = temp >> 24;
        iap->option_byte[4 * i + 4] = temp >> 16;
        iap->option_byte[4 * i + 3] = temp >> 8;
        iap->option_byte[4 * i + 2] = temp;
        option_address = option_address + 4U;
    }
    iap->option_byte[1] = OPERATION_SUCCESS;

    iap_report_send(udev, iap->option_byte, IAP_IN_PACKET);
}

Fix file:
..\Firmware\GD32F3X0_usbd_library\device\class\iap\Source\usb_iap_core.c
fix reason: 
Changing leave IAP mode request function due to IAP protocol modification
V2.3.0:
/*!
    \brief      handle the IAP_LEAVE request
    \param[in]  udev: pointer to usb device instance
    \param[out] none
    \retval     none
*/
static void iap_req_leave(usb_dev *udev)
{
    /* lock the internal flash */
    fmc_lock();

    /* generate system reset to allow jumping to the user code */
    NVIC_SystemReset();
}
V2.4.0:
/*!
    \brief      handle the IAP_LEAVE request
    \param[in]  udev: pointer to USB device instance
    \param[out] none
    \retval     none
*/
static void iap_req_leave(usb_dev *udev)
{
    usbd_iap_handler *iap = (usbd_iap_handler *)udev->dev.class_data[USBD_IAP_INTERFACE];

    /* get base address to jump */
    iap->base_address  = iap->report_buf[2];
    iap->base_address |= (uint32_t)iap->report_buf[3] << 8;
    iap->base_address |= (uint32_t)iap->report_buf[4] << 16;
    iap->base_address |= (uint32_t)iap->report_buf[5] << 24;

    iap->dev_status[0] = IAP_DEVICE_ID;
    iap->dev_status[1] = LEAVE_FINISH;

    usbd_ep_send(udev, IAP_IN_EP, iap->dev_status, IAP_IN_PACKET);

    usbd_disconnect(udev);

    /* reset register */
    register_reset();

    /* jump to target */
    jump_to_execute(iap->base_address);
}

Fix file:
..\Firmware\GD32F3X0_usbd_library\device\class\iap\Source\usb_iap_core.c
fix reason: 
Changing IAP upload request function due to IAP protocol modification
V2.3.0:
none
V2.4.0:
/*!
    \brief      handle the IAP_UPLOAD request
    \param[in]  udev: pointer to USB device instance
    \param[out] none
    \retval     none
*/
static void iap_req_upload(usb_dev *udev)
{
    uint16_t packet_valid_length = 0U, i= 0U;
    uint32_t bin_flash_addr = APP_LOADED_ADDR;
    usbd_iap_handler *iap = (usbd_iap_handler *)udev->dev.class_data[USBD_IAP_INTERFACE];

    iap->bin_addr[0] = IAP_DEVICE_ID;

    /* get target flash address */
    bin_flash_addr  = iap->report_buf[2];
    bin_flash_addr |= (uint32_t)iap->report_buf[3] << 8;
    bin_flash_addr |= (uint32_t)iap->report_buf[4] << 16;
    bin_flash_addr |= (uint32_t)iap->report_buf[5] << 24;

    /* get current packet valid length */
    packet_valid_length = iap->report_buf[6];
    packet_valid_length |= iap->report_buf[7] << 8;

    /* get target flash address content */
    for(i = 0U; i < packet_valid_length; i++) {
        iap->bin_addr[i + 1] = REG8(bin_flash_addr + i);
    }

    iap_report_send(udev, iap->bin_addr, IAP_IN_PACKET);
}

Fix file:
..\Firmware\GD32F3X0_usbd_library\device\class\iap\Source\usb_iap_core.c
fix reason: 
Adding IAP check read protected request function due to IAP protocol modification
V2.3.0:
none
V2.4.0:
/*!
    \brief      handle the IAP_CHECK_RDP request
    \param[in]  udev: pointer to USB device instance
    \param[out] none
    \retval     none
*/
static void iap_check_rdp(usb_dev *udev)
{
    uint8_t mode = 0U;
    usbd_iap_handler *iap = (usbd_iap_handler *)udev->dev.class_data[USBD_IAP_INTERFACE];

    /* check whether the SPC bit of FMC module is normal state */
    if(0xA5U != REG8(OPT_BYTE_ADDR)) {
        mode = IS_RDP_MODE;
    } else {
        mode = IS_NORMAL_MODE;
    }

    iap->bin_addr[0] = IAP_DEVICE_ID;
    iap->bin_addr[1] = mode;

    iap_report_send(udev, iap->bin_addr, IAP_IN_PACKET);
}

Fix file:
..\Firmware\GD32F3X0_usbd_library\device\class\msc\Include\usbd_msc_scsi.h
fix reason: 
The statement here can be removed
V2.3.0:
extern const uint8_t msc_page00_inquiry_data[];
extern const uint8_t msc_mode_sense6_data[];
extern const uint8_t msc_mode_sense10_data[];
V2.4.0:
none

Fix file:
..\Firmware\GD32F3X0_usbd_library\usbd\Include\usbd_lld_regs.h
fix reason: 
MCU register operation is a read-modify-write-back process, and RX_ST and TX_ST in the
USBD_EPxCS register are write 0 valid, write 1 invalid bits, so that if RX_ST and TX_ST
are 0 when reading out the USBD_EPxCS register, and the hardware will set RT_ST or TX_ST
when rewriting the value of the register, then the write-back process This interrupt has
not yet been processed, resulting in lost interrupt processing.
V2.3.0:
#define USBD_EP_TX_STAT_SET(ep, stat) do {\
    USBD_EPxCS(ep) = (USBD_EPxCS(ep) & (uint16_t)EPTX_DTGMASK) ^ (stat); \
} while(0)

#define USBD_EP_RX_STAT_SET(ep, stat) do {\
    USBD_EPxCS(ep) = (USBD_EPxCS(ep) & (uint16_t)EPRX_DTGMASK) ^ (stat); \
} while(0)

/* clear bit EPxCS_RX_ST/EPxCS_TX_ST in the endpoint control and status register */

#define USBD_EP_TX_ST_CLEAR(ep) do {\
    USBD_EPxCS(ep) &= ~EPxCS_TX_ST & (uint16_t)EPCS_MASK; \
} while(0)

#define USBD_EP_RX_ST_CLEAR(ep) do {\
    USBD_EPxCS(ep) &= ~EPxCS_RX_ST & (uint16_t)EPCS_MASK; \
} while(0)

/* toggle EPxCS_RX_DTG or EPxCS_TX_DTG bit in the endpoint control and status register */

#define USBD_TX_DTG_TOGGLE(ep) do {\
    USBD_EPxCS(ep) = EPxCS_TX_DTG | (USBD_EPxCS(ep) & EPCS_MASK); \
} while(0)

#define USBD_RX_DTG_TOGGLE(ep) do {\
    USBD_EPxCS(ep) = EPxCS_RX_DTG | (USBD_EPxCS(ep) & EPCS_MASK); \
} while(0)

/* clear EPxCS_RX_DTG or EPxCS_TX_DTG bit in the endpoint control and status register */

#define USBD_TX_DTG_CLEAR(ep) do {\
    if ((USBD_EPxCS(ep_num) & EPxCS_TX_DTG) != 0U) {\
        USBD_TX_DTG_TOGGLE(ep);\
    } \
} while(0)

#define USBD_RX_DTG_CLEAR(ep) do {\
    if ((USBD_EPxCS(ep_num) & EPxCS_RX_DTG) != 0U) {\
        USBD_RX_DTG_TOGGLE(ep);\
    } \
} while(0)

#define USBD_EP_DBL_BUF_SET(ep) (USBD_EPxCS(ep) = (USBD_EPxCS(ep) | EPxCS_KCTL) & EPCS_MASK)
V2.4.0:
#define USBD_EP_TX_STAT_SET(ep, stat) do { \
    uint16_t regval; \
    regval = (USBD_EPxCS(ep) & (uint16_t)EPTX_DTGMASK) ^ (stat); \
    USBD_EPxCS(ep) = regval | EPxCS_RX_ST | EPxCS_TX_ST; \
} while(0)

#define USBD_EP_RX_STAT_SET(ep, stat) do { \
    uint16_t regval; \
    regval = (USBD_EPxCS(ep) & (uint16_t)EPRX_DTGMASK) ^ (stat); \
    USBD_EPxCS(ep) = regval | EPxCS_RX_ST | EPxCS_TX_ST; \
} while(0)

/* clear bit EPxCS_RX_ST/EPxCS_TX_ST in the endpoint control and status register */

#define USBD_EP_TX_ST_CLEAR(ep) do { \
    uint16_t regval; \
    regval = USBD_EPxCS(ep) & (~EPxCS_TX_ST & (uint16_t)EPCS_MASK); \
    USBD_EPxCS(ep) = regval | EPxCS_RX_ST; \
} while(0)

#define USBD_EP_RX_ST_CLEAR(ep) do { \
    uint16_t regval; \
    regval = USBD_EPxCS(ep) & (~EPxCS_RX_ST & (uint16_t)EPCS_MASK); \
    USBD_EPxCS(ep) = regval | EPxCS_TX_ST; \
} while(0)

/* toggle EPxCS_RX_DTG or EPxCS_TX_DTG bit in the endpoint control and status register */

#define USBD_TX_DTG_TOGGLE(ep) do { \
    uint16_t regval; \
    regval = EPxCS_TX_DTG | (USBD_EPxCS(ep) & EPCS_MASK); \
    USBD_EPxCS(ep) = regval | EPxCS_RX_ST | EPxCS_TX_ST; \
} while(0)

#define USBD_RX_DTG_TOGGLE(ep) do { \
    uint16_t regval; \
    regval = EPxCS_RX_DTG | (USBD_EPxCS(ep) & EPCS_MASK); \
    USBD_EPxCS(ep) = regval | EPxCS_RX_ST | EPxCS_TX_ST; \
} while(0)

/* clear EPxCS_RX_DTG or EPxCS_TX_DTG bit in the endpoint control and status register */

#define USBD_TX_DTG_CLEAR(ep) do { \
    if(0U != (USBD_EPxCS(ep) & EPxCS_TX_DTG)) { \
        USBD_TX_DTG_TOGGLE(ep); \
    } \
} while(0)

#define USBD_RX_DTG_CLEAR(ep) do { \
    if(0U != (USBD_EPxCS(ep) & EPxCS_RX_DTG)) { \
        USBD_RX_DTG_TOGGLE(ep); \
    } \
} while(0)

#define USBD_EP_DBL_BUF_SET(ep) do { \
    uint16_t regval; \
    regval = (USBD_EPxCS(ep) | EPxCS_KCTL) & EPCS_MASK; \
    USBD_EPxCS(ep) = regval | EPxCS_RX_ST | EPxCS_TX_ST; \
} while(0)


Fix file:
..\Firmware\GD32F3X0_usbd_library\usbd\Source\usbd_lld_core.c
fix reason: 
RBCNT register configuration error
V2.3.0:
btable_ep[ep_num].rx_count = ((uint16_t)((uint16_t)transc->max_len << 5) - 1U) | 0x8000U;
V2.4.0:
if (transc->max_len & 0x1FU) {
	btable_ep[ep_num].rx_count = (((uint16_t)transc->max_len >> 5) << 10) | 0x8000U; 
} else {
	btable_ep[ep_num].rx_count = ((((uint16_t)transc->max_len >> 5) - 1U) << 10) | 0x8000U; 
}

_____________________________________________________________________________________________________________________


__________________________________________________________________________________________________________________________

